﻿#ifndef UDPCONTROLLER_H
#define UDPCONTROLLER_H

#include <qobject.h>
#include "ObjAutoInject.h"
#include <qhash.h>
#include <qlist.h>
#include <qtimer.h>

class UdpCodec;
class DeliveredRecord;
class Mapper_Test_RTT;
class Mapper_testDataByTime;
class RegisterCenter_Device;
class DataPackage_UdpCodec;
class UdpController : public QObject,public ObjAutoInject
{
  Q_OBJECT
  friend class DeliveredRecord;
private://test
  int sendInterval=333;
  int dataSize=21;
  //test
  QTimer test;
  ushort msgId=0;
private://property
  //------------各个模块开关-------------
  bool active_bbr = true;//BBR拥塞控制的开关
  bool active_rto = true;//超时重传开关
  //------------------------------------

  //----------------------发送队列相关----------------------------
  int bufferLimit=5;
  QList<DataPackage_UdpCodec*> dataPackageListBuffer;//发送队列
  QHash<uint/*hash value*/,QTimer*> inflightTimer;//超时计时器
  QHash<uint/*hash value*/,DataPackage_UdpCodec*> inflightDataPackage;//等待缓冲区
  //-------------------------------------------------------------

  //---------------------------NB默认通信参数--------------------------------------
  int rtt_init=1500;//rtt的初始化值，取测试中测得的坏值
  int bw_init=60;//bw的初始化值
  int rto_min=2000;//最小超时重传时间，毫秒，这里取三至四倍测试中正常RTT值
  //-----------------------------------------------------------------------------

  //------------------------TCP经典参数计算---------------------------------------
  int rtt=rtt_init;
  int bw=bw_init<<3;//滑动平均bw，为防止浮点操作，这里的字面值是实际值的8倍
  int rtt_ave=rtt_init<<3;//滑动平均RTT，初始值取测试中正常延时的三倍,为了防止浮点操作这里的字面值是实际值的8倍。
  int rtt_mdev=rtt_init<<1;//RTT的标准差
  int rtt_maxMdev=rtt_mdev;//单次RTT内最大mdev
  int rtt_var=rtt_mdev;//mdev_max的平滑值
  int rto=rtt_init+rtt_mdev;//当前超时重传时间，按照TCP协议中的计算方法，初始值取三倍的rtt
  int currentRttCycle_TCP=0;//当前rtt周期下标
  QTimer timer_rttCycle;//rtt周期超时计时器
  QList<ushort/*timestamp*/> rttCycleList;//记录当前周期内数据包的发送时间
  //----------------------------------------------------------------------------

  //-------------------------BBR参数计算------------------------------------------------
  int rtt_min=rtt_ave;//RTT最小值，单位：毫秒，初始值取测试中正常延时的三倍，为了防止浮点操作这里的字面值是实际值的8倍。
  int bw_ave=bw;//BW最大值，单位：字节/秒。为了防止浮点操作这里的字面值是实际值的8倍。
  int bdp=0;//拥塞窗口大小,单位：字节。
  int inflight=0;
  int delivered=0;
  int delivered_time=0;
  QHash<ushort/*sendTime*/,DeliveredRecord*> deliveredRecordMap;//用于计算BW
  QHash<int/*cwndGainIndex*/,float/*gain*/> cwndGainMap;//拥塞窗口增益
  int cwndGainIndex=0;//增益下标
  QHash<int/*pacingGainIndex*/,float/*gain*/> pacingGainMap;//带宽增益
  int pacingGainIndex=0;//增益下标
  //---------------------------------------------------------------------------------

  //--------------------------------数据库记录相关-----------------------------------
  QTimer timer_dataByTime;

  int delivered_record = delivered;
  //--------------------------------------------------------------------------------

private://dependency
  UdpCodec* udpCodec=Q_NULLPTR;
  Mapper_Test_RTT* mapper_Test_RTT=Q_NULLPTR;
  RegisterCenter_Device* registerCenter_Device = Q_NULLPTR;
  Mapper_testDataByTime* mapper_testDataByTime = Q_NULLPTR;
public:
  explicit UdpController();
  virtual ~UdpController();
signals:
public:
  void send(DataPackage_UdpCodec* dataPackage_UdpCodec,bool emergency=false);
  bool receive(DataPackage_UdpCodec* dataPackage_UdpCodec);

  bool isCongestion();
  bool isActive_bbr();
  bool isActive_rto();
private slots:
  void slot_sendTestData();
  void slot_deviceOnline();
  void slot_deviceOffline();
  void slot_rttCycleEnd();//rtt周期结束时的处理
  void slot_dataPackageTimeout(uint hashValue);//更新数据包超时时间
  void slot_dataByTime();
private:
  void sendDataPackage(DataPackage_UdpCodec* dataPackage_UdpCodec);
  void trySend();
  void addToInflightList(DataPackage_UdpCodec* dataPackage_UdpCodec);
  void updateTcpAndBbr(DataPackage_UdpCodec* dataPackage_UdpCodec);
  void updateRto(int rtt);
  void updateTimeoutTimer();
public://geter and seter
  UdpCodec* getUdpCodec()const;
  UdpController* setUdpCodec(UdpCodec*const udpCodec);
  Mapper_Test_RTT* getMapper_Test_RTT()const;
  UdpController* setMapper_Test_RTT(Mapper_Test_RTT*const mapper_Test_RTT);
  RegisterCenter_Device* getRegisterCenter_Device()const;
  UdpController* setRegisterCenter_Device(RegisterCenter_Device*const registerCenter_Device);
  Mapper_testDataByTime* getMapper_testDataByTime()const;
  UdpController* setMapper_testDataByTime(Mapper_testDataByTime*const mapper_testDataByTime);
public:
  virtual void objectAutoInjection(QHash<QString,QObject*>* objMap)override;
};
class DeliveredRecord:public QObject
{
  Q_OBJECT
  friend class UdpController;
private:
  ushort timeStamp = 0;
  int delivered = 0;
  ushort time = 0;
  QTimer timer;
  UdpController* udpController=Q_NULLPTR;
private:
  explicit DeliveredRecord()
  {
    connect(&timer,&QTimer::timeout,this,&DeliveredRecord::slot_delete);
  }
  virtual ~DeliveredRecord(){}
private slots:
  void slot_delete()
  {
    delete udpController->deliveredRecordMap.take(timeStamp);
  }
private:
  void startAutoDelete(int msec)
  {
    timer.start(msec);
  }
  void stopAutoDelete()
  {
    timer.stop();
  }
private:
  ushort getTimeStamp()
  {
    return timeStamp;
  }
  DeliveredRecord* setTimeStamp(ushort timeStamp)
  {
    this->timeStamp=timeStamp;
    return this;
  }
  uint getDelivered()
  {
    return delivered;
  }
  DeliveredRecord* setDelivered(uint delivered)
  {
    this->delivered=delivered;
    return this;
  }
  ushort getTime()
  {
    return time;
  }
  DeliveredRecord* setTime(ushort time)
  {
    this->time=time;
    return this;
  }
  UdpController* getUdpController()const
  {
    return udpController;
  }
  DeliveredRecord* setUdpController(UdpController* const udpController)
  {
    this->udpController=udpController;
    return this;
  }
};
#endif // UDPCONTROLLER_H
